package core;

import utils.UnSafeUtils;

import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;

public class SqlInstancePool {

	static final String JDBC_DRIVER="com.mysql.cj.jdbc.Driver";

	static final String URL="jdbc:mysql://120.46.147.78:3366/test?useUnicode=true&characterEncoding=utf8&nullCatalogMeansCurrent=true&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai";

	static final String USER="root";

	static final String PASS="123456";

	private List <SqlInstance> pool = new ArrayList<>();

	private Semaphore semaphore;

	// 初始化pool
	public SqlInstancePool initPool(int n) throws SQLException, ClassNotFoundException, NoSuchFieldException {
		Class.forName(JDBC_DRIVER);
		for (int i = 0; i < n; i++) {
			pool.add(new SqlInstance(DriverManager.getConnection(URL, USER, PASS),0,"name-"+i));
		}
		semaphore=new Semaphore(n);
		return this;
	}


	private void execute(String sql) throws SQLException, InterruptedException {
		semaphore.acquire();
		for (SqlInstance sqlInstance : pool) {
			if(setState1(sqlInstance)){
				sqlInstance.execute(sql);
				setState0(sqlInstance);
				break;
			}
		}
	}

	private boolean setState1(SqlInstance sqlInstance){
		return UnSafeUtils.unsafe.compareAndSwapInt(sqlInstance, sqlInstance.offset, 0, 1);
	}

	private void setState0(SqlInstance sqlInstance){
		UnSafeUtils.unsafe.compareAndSwapInt(sqlInstance, sqlInstance.offset, 1, 0);
		semaphore.release();
	}


	public static void main(String[] args) throws SQLException, NoSuchFieldException, ClassNotFoundException, InterruptedException {
		SqlInstancePool sqlInstancePool = new SqlInstancePool().initPool(15);
		int threadNum=150;
		CountDownLatch countDownLatch = new CountDownLatch(threadNum);
		long start = System.currentTimeMillis();
		for (int i = 0; i < threadNum; i++) {
			int finalI = i;
			Thread.ofVirtual().factory().newThread(()->{
				try {
					sqlInstancePool.execute("update user_info set password = '"+ finalI +"' where id = 1");
					countDownLatch.countDown();
				} catch (SQLException | InterruptedException e) {
					throw new RuntimeException(e);
				}
			}).start();
		}
		countDownLatch.await();

		System.out.println("耗时："+(System.currentTimeMillis()-start));
		// 耗时根据sql耗时，当sql耗时不多，极少的连接数就可以达到瓶颈，当sql耗时多时，连接数越多速度越快

		while (true);
	}

}
